<?php

    // 应用公共文件
    use think\facade\Session;
    use think\facade\Db;

    // 应用公共文件
    /**
     * 数组转xls格式的excel文件
     * @param $data
     * @param $title
     * 示例数据
     * $data = [
     *     [NULL, 2010, 2011, 2012],
     *     ['Q1', 12, 15, 21],
     *     ['Q2', 56, 73, 86],
     *     ['Q3', 52, 61, 69],
     *     ['Q4', 30, 32, 10],
     * ];
     * @throws PHPExcel_Exception
     * @throws PHPExcel_Reader_Exception
     * @throws PHPExcel_Writer_Exception
     */
    function export_excel($data, $title,$filename)
    {
        //require_once __DIR__ . '/vendor/autoload.php';

        // Create new Spreadsheet object
        $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        // 方法一，使用 setCellValueByColumnAndRow
        //表头
        //设置单元格内容
        foreach ($title as $key => $value) {
            // 单元格内容写入
            $sheet->setCellValueByColumnAndRow($key + 1, 1, $value);
        }
        $row = 2; // 从第二行开始
        foreach ($data as $item) {
            $column = 1;
            foreach ($item as $value) {
                // 单元格内容写入
                $sheet->setCellValueByColumnAndRow($column, $row, $value);
                $column++;
            }
            $row++;
        }

        // 方法二，使用 setCellValue
        //表头
        //设置单元格内容
        $titCol = 'A';
        foreach ($title as $key => $value) {
            // 单元格内容写入
            $sheet->setCellValue($titCol . '1', $value);
            $titCol++;
        }
        $row = 2; // 从第二行开始
        foreach ($data as $item) {
            $dataCol = 'A';
            foreach ($item as $value) {
                // 单元格内容写入
                $sheet->setCellValue($dataCol . $row, $value);
                $dataCol++;
            }
            $row++;
        }

        // Redirect output to a client’s web browser (Xlsx)
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="'.$filename.'.xlsx"');
        header('Cache-Control: max-age=0');
        // If you're serving to IE 9, then the following may be needed
        header('Cache-Control: max-age=1');

        // If you're serving to IE over SSL, then the following may be needed
        header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); // Date in the past
        header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . ' GMT'); // always modified
        header('Cache-Control: cache, must-revalidate'); // HTTP/1.1
        header('Pragma: public'); // HTTP/1.0

        $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
        $writer->save('php://output');
        exit;
    }

    /**
     * 使用PHPEXECL导入
     *
     * @param string $file      文件地址
     * @param int    $sheet     工作表sheet(传0则获取第一个sheet)
     * @param int    $columnCnt 列数(传0则自动获取最大列)
     * @param array  $options   操作选项
     *                          array mergeCells 合并单元格数组
     *                          array formula    公式数组
     *                          array format     单元格格式数组
     *
     * @return array
     * @throws Exception
     */
    function import_execl($file = '', $sheet = 0, $columnCnt = 0, &$options = [])
    {
        try {
            /* 转码 */
            $file = iconv("utf-8", "gb2312", $file);

            if (empty($file) OR !file_exists($file)) {
                $msg['code'] = 0;
                $msg['tips'] = '文件不存在!';
                return $msg;
                //throw new \Exception('文件不存在!');
            }
            /** @var Xlsx $objRead */
            $objRead = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xlsx');

            if (!$objRead->canRead($file)) {
                /** @var Xls $objRead */
                $objRead = \PhpOffice\PhpSpreadsheet\IOFactory::createReader('Xls');

                if (!$objRead->canRead($file)) {
                    $msg['code'] = 0;
                    $msg['tips'] = '只支持导入Excel文件!';
                    return $msg;
                    //throw new \Exception('只支持导入Excel文件！');
                }
            }

            /* 如果不需要获取特殊操作，则只读内容，可以大幅度提升读取Excel效率 */
            empty($options) && $objRead->setReadDataOnly(true);
            /* 建立excel对象 */
            $obj = $objRead->load($file);
            /* 获取指定的sheet表 */
            $currSheet = $obj->getSheet($sheet);

            if (isset($options['mergeCells'])) {
                /* 读取合并行列 */
                $options['mergeCells'] = $currSheet->getMergeCells();
            }

            if (0 == $columnCnt) {
                /* 取得最大的列号 */
                $columnH = $currSheet->getHighestColumn();
                /* 兼容原逻辑，循环时使用的是小于等于 */
                $columnCnt = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::columnIndexFromString($columnH);
            }

            /* 获取总行数 */
            $rowCnt = $currSheet->getHighestRow();
            $data   = [];

            /* 读取内容 */
            for ($_row = 1; $_row <= $rowCnt; $_row++) {
                $isNull = true;

                for ($_column = 1; $_column <= $columnCnt; $_column++) {
                    $cellName = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::stringFromColumnIndex($_column);
                    $cellId   = $cellName . $_row;
                    $cell     = $currSheet->getCell($cellId);

                    if (isset($options['format'])) {
                        /* 获取格式 */
                        $format = $cell->getStyle()->getNumberFormat()->getFormatCode();
                        /* 记录格式 */
                        $options['format'][$_row][$cellName] = $format;
                    }

                    if (isset($options['formula'])) {
                        /* 获取公式，公式均为=号开头数据 */
                        $formula = $currSheet->getCell($cellId)->getValue();

                        if (0 === strpos($formula, '=')) {
                            $options['formula'][$cellName . $_row] = $formula;
                        }
                    }

                    if (isset($format) && 'm/d/yyyy' == $format) {
                        /* 日期格式翻转处理 */
                        $cell->getStyle()->getNumberFormat()->setFormatCode('yyyy/mm/dd');
                    }

                    $data[$_row][$cellName] = trim($currSheet->getCell($cellId)->getFormattedValue());

                    if (!empty($data[$_row][$cellName])) {
                        $isNull = false;
                    }
                }

                /* 判断是否整行数据为空，是的话删除该行数据 */
                if ($isNull) {
                    unset($data[$_row]);
                }
            }
            return $data;

        } catch (\Exception $e) {
            throw $e;
        }
    }

    /**
     * http请求
     * @param string $url 请求的地址
     * @param array $data 发送的参数
     */
    function https_request($url, $data = null)
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
        if (!empty($data)) {
            curl_setopt($curl, CURLOPT_POST, TRUE);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
        $output = curl_exec($curl);
        curl_close($curl);
        return $output;
    }

    /**
     * 格式化字节大小
     * @param  number $size      字节数
     * @param  string $delimiter 数字和单位分隔符
     * @return string            格式化后的带单位的大小
     */
    function format_bytes($size, $delimiter = '') {
        $units = array('B', 'KB', 'MB', 'GB', 'TB', 'PB');
        for ($i = 0; $size >= 1024 && $i < 5; $i++) $size /= 1024;
        return round($size, 2) . $delimiter . $units[$i];
    }
    /**
     * 把json字符串转数组
     * @param json $p
     * @return array
     */
    function json_to_array($p)
    {
        if (mb_detect_encoding($p, array('ASCII', 'UTF-8', 'GB2312', 'GBK')) != 'UTF-8') {
            $p = iconv('GBK', 'UTF-8', $p);
        }
        return json_decode($p, true);
    }
    /**
     * 把json字符串转数组
     * @param num $code
     * @param string $msg
     * @param object $data
     * @return json
     */
    function think_json($code,$msg="",$data=array()){
        $result=array(
           'code'=>$code,
           'msg'=>$msg,
           'count'=>count($data),
           'data'=>$data
        );
        //输出json
        return json_encode($result);
    }

    // 生成唯一订单号
    function build_order_no()
    {
        return date('Ymd') . substr(implode(null, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 15);
    }

    /**
     * 获取随机位数数字
     * @param  integer $len 长度
     * @return string
     */
    function rand_number($len = 6)
    {
        return substr(str_shuffle(str_repeat('0123456789', 10)), 0, $len);
    }
    /**
     * 获取随机位数汉字
     * @param  integer $len 长度
     * @return string
     */
    function getChar($len){
        $b = '';
        for ($i=0; $i<$len; $i++) {
            // 使用chr()函数拼接双字节汉字，前一个chr()为高位字节，后一个为低位字节
            $a = chr(mt_rand(0xB0,0xD0)).chr(mt_rand(0xA1, 0xF0));
            // 转码
            $b .= iconv('GB2312', 'UTF-8', $a);
        }
        return $b;
    }
    /**
     * 验证手机验证码
     * @param  integer $value 手机号
     * @param  integer $code  验证码
     * @return boolean
     */
    function check_code($value,$code)
    {
        $vercode = Session::get('"'.$value.'"');
        if($vercode != $code){
            return false;
        }
        return true;
    }

    /**
     * 验证密码长度
     * @param string $password 需要验证的密码
     * @param int $min 最小长度
     * @param int $max 最大长度
     */
    function check_password($password, $min, $max)
    {
        if (strlen($password) < $min || strlen($password) > $max) {
            return false;
        }
        return true;
    }
    /**
     * 加密方式
     * @param string $value 需要加密的字串
     * @param $salt //传入加密串，在修改密码时做认证
     * @return array/password
     */
    function morse_code($value, $salt='') {
        $pwd = array();
        $pwd['salt'] =  $salt ? $salt : create_randomstr();
        $pwd['password'] = md5(substr(md5(trim($value)),0,16).$pwd['salt']);
        return $salt ? $pwd['password'] : $pwd;
    }

    /**
     * 生成随机字符串
     * @param string $lenth 长度
     * @return string 字符串
     */
    function create_randomstr($length = 6) {
        if(!is_int($length) || $length < 0) {
            return false;
        }
        $char = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $string = '';
        for($i = $length; $i > 0; $i--) {
            $string .= $char[mt_rand(0, strlen($char) - 1)];
        }
     
        return $string;
    }
    /**
     * 验证固定电话格式
     * @param string $tel 固定电话
     * @return boolean
     */
    function check_tel($tel) {
        $chars = "/^([0-9]{3,4}-)?[0-9]{7,8}$/";
        if (preg_match($chars, $tel)) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 验证身份证号格式
     * @param string $value 身份证格式
     * @return boolean
     */
    function check_card($value) {
        $preg_card='/(^\d{15}$)|(^\d{17}([0-9]|X)$)/isu';
        if(preg_match($preg_card,$value)){
            return true;
        } else {
            return false;
        }
    }

    /**
     * 验证中英文名称格式
     * @param string $value 中英文
     * @return boolean
     */
    function check_name($value) {
        $preg_name='/^[\x{4e00}-\x{9fa5}]{2,10}$|^[a-zA-Z\s]*[a-zA-Z\s]{2,20}$/isu';
        if (preg_match($preg_name, $value)) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 验证输入的手机号码是否合法
     *
     * @access public
     * @param string $mobile_phone 需要验证的手机号码
     * @return bool
     */
    function is_mobile_phone($phone)
    {
        $chars = "/^13[0-9]{1}[0-9]{8}$|14[0-9]{1}[0-9]{8}$|15[0-9]{1}[0-9]{8}$|16[0-9]{1}[0-9]{8}$|17[0-9]{1}[0-9]{8}$|18[0-9]{1}[0-9]{8}$|19[0-9]{1}[0-9]{8}$/";
        if (strlen($phone) == 11 && is_numeric($phone)) {
            if(preg_match($chars, $phone)){
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    }

    /**
     * 验证QQ号码是否正确
     * @param number $qq
     */
    function check_qq($qq)
    {
        if (!is_numeric($qq)) {
            return false;
        }
        return true;
    }
    /*
     * 数字金额转换成中文大写金额的函数
     * String Int  $num  要转换的小写数字或小写字符串
     * return 大写数字
     */
    function num_to_rmb($num){
        $c1 = "零壹贰叁肆伍陆柒捌玖";
        $c2 = "分角元拾佰仟万拾佰仟亿";
        //精确到分后面就不要了，所以只留两个小数位
        $num = round($num, 2);
        //将数字转化为整数
        $num = $num * 100;//12312
        if (strlen($num) > 10) {
            return "金额太大，请检查";
        }
        $i = 0;
        $c = "";
        while (1) {
            if ($i == 0) {
                //获取最后一位数字
                $n = substr($num, strlen($num)-1, 1);
            } else {
                $n = $num % 10;
            }
            //每次将最后一位数字转化为中文
            $p1 = substr($c1, 3 * $n, 3);
            $p2 = substr($c2, 3 * $i, 3);
            if ($n != '0' || ($n == '0' && ($p2 == '亿' || $p2 == '万' || $p2 == '元'))) {
                $c = $p1 . $p2 . $c;
            } else {
                $c = $p1 . $c;
            }
            $i = $i + 1;
            //去掉数字最后一位了
            $num = $num / 10;
            $num = (int)$num;
            //结束循环
            if ($num == 0) {
                break;
            }
        }
        $j = 0;
        $slen = strlen($c);
        while ($j < $slen) {
            //utf8一个汉字相当3个字符
            $m = substr($c, $j, 6);
            //处理数字中很多0的情况,每次循环去掉一个汉字“零”
            if ($m == '零元' || $m == '零万' || $m == '零亿' || $m == '零零') {
                $left = substr($c, 0, $j);
                $right = substr($c, $j + 3);
                $c = $left . $right;
                $j = $j-3;
                $slen = $slen-3;
            }
            $j = $j + 3;
        }
        //这个是为了去掉类似23.0中最后一个“零”字
        if (substr($c, strlen($c)-3, 3) == '零') {
            $c = substr($c, 0, strlen($c)-3);
        }
        //将处理的汉字加上“整”
        if (empty($c)) {
            return "零元整";
        }else{
            return $c . "整";
        }
    }
    /**
     * 配置值解析成数组
     * @param string $value 配置值
     * @return array|string
     */
    function parse_attr($value)
    {
        if (is_array($value)) {
            return $value;
        }
        $array = preg_split('/[,;\r\n]+/', trim($value, ",;\r\n"));
        if (strpos($value, ':')) {
            $value = array();
            foreach ($array as $val) {
                list($k, $v) = explode(':', $val);
                $value[$k] = $v;
            }
        } else {
            $value = $array;
        }
        return $value;
    }

    /**
     * 数组层级缩进转换
     * @param array $array 源数组
     * @param int $pid
     * @param int $level
     * @return array
     */
    function list_to_level($array, $pid = 0, $level = 1)
    {
        static $list = [];
        foreach ($array as $k => $v) {
            if ($v['pid'] == $pid) {
                $v['level'] = $level;
                $list[]     = $v;
                unset($array[$k]);
                list_to_level($array, $v['id'], $level + 1);
            }
        }
        return $list;
    }

    /**
     * 把返回的数据集转换成Tree
     * @param array $list 要转换的数据集
     * @param string $pid parent标记字段
     * @param string $level level标记字段
     * @return array
     * @author 麦当苗儿 <zuojiazi@vip.qq.com>
     */
    function list_to_tree($list, $pk = 'id', $pid = 'pid', $child = 'children', $root = 0)
    {
        // 创建Tree
        $tree = array();
        if(is_array($list)) {
            // 创建基于主键的数组引用
            $refer = array();
            foreach ($list as $key => $data) {
                $refer[$data[$pk]] =& $list[$key];
            }
            foreach ($list as $key => $data) {
                // 判断是否存在parent
                $parentId = $data[$pid];
                if ($root == $parentId) {
                    $tree[] =& $list[$key];               
     
                }else{
                    if (isset($refer[$parentId])) {
                        $parent =& $refer[$parentId];
                        $parent[$child][] =& $list[$key];
                    }
                }
            }
        }
        return $tree;
    }

    /**
     * 将list_to_tree的树还原成列表
     * @param  array $tree 原来的树
     * @param  string $child 孩子节点的键
     * @param  string $order 排序显示的键，一般是主键 升序排列
     * @param  array $list 过渡用的中间数组，
     * @return array        返回排过序的列表数组
     * @author yangweijie <yangweijiester@gmail.com>
     */
    function tree_to_list($tree, $child = 'children', $order = 'id', &$list = array())
    {
        if (is_array($tree)) {
            $refer = array();
            foreach ($tree as $key => $value) {
                $reffer = $value;
                if (isset($reffer[$child])) {
                    unset($reffer[$child]);
                    tree_to_list($value[$child], $child, $order, $list);
                }
                $list[] = $reffer;
            }
            $list = list_sort_by($list, $order, $sortby = 'asc');
        }
        return $list;
    }

    /**
     * 对查询结果集进行排序
     * @access public
     * @param array $list 查询结果
     * @param string $field 排序的字段名
     * @param array $sortby 排序类型
     * asc正向排序 desc逆向排序 nat自然排序
     * @return array
     */
    function list_sort_by($list, $field, $sortby = 'asc')
    {
        if (is_array($list)) {
            $refer = $resultSet = array();
            foreach ($list as $i => $data) {
                $refer[$i] = &$data[$field];
            }

            switch ($sortby) {
                case 'asc': // 正向排序
                    asort($refer);
                    break;
                case 'desc': // 逆向排序
                    arsort($refer);
                    break;
                case 'nat': // 自然排序
                    natcasesort($refer);
                    break;
            }
            foreach ($refer as $key => $val) {
                $resultSet[] = &$list[$key];
            }

            return $resultSet;
        }
        return false;
    }

    // 驼峰命名法转下划线风格
    function to_under_score($str)
    {
        $array = array();
        for ($i = 0; $i < strlen($str); $i++) {
            if ($str[$i] == strtolower($str[$i])) {
                $array[] = $str[$i];
            } else {
                if ($i > 0) {
                    $array[] = '_';
                }
                $array[] = strtolower($str[$i]);
            }
        }
        $result = implode('', $array);
        return $result;
    }

    /**
     * 自动生成新尺寸的图片
     * @param string $filename 文件名
     * @param int $width 新图片宽度
     * @param int $height 新图片高度(如果没有填写高度，把高度等比例缩小)
     * @param int $type 缩略图裁剪类型
     * 1 => 等比例缩放类型
     * 2 => 缩放后填充类型
     * 3 => 居中裁剪类型
     * 4 => 左上角裁剪类型
     * 5 => 右下角裁剪类型
     * 6 => 固定尺寸缩放类型
     * @return string     生成缩略图的路径
     */
    function thumb($src = '', $width = 500, $height = 500, $type = 1, $replace = false)
    {
        //判断URL
        if(strstr($src, request()->domain())){
            $src = './' .str_replace(request()->domain(),'',$src);
        }else{
            $src = './' . $src;
        }
        if (is_file($src) && file_exists($src)) {
            // 如果没有填写高度，把高度等比例缩小
            if ($height == null) {
                $info = getimagesize(root_path() . $filename);
                if ($width > $info[0]) {
                    // 如果缩小后宽度尺寸大于原图尺寸，使用原图尺寸
                    $width  = $info[0];
                    $height = $info[1];
                } elseif ($width < $info[0]) {
                    $height = floor($info[1] * ($width / $info[0]));
                } elseif ($width == $info[0]) {
                    return $filename;
                }
            }
            $ext = pathinfo($src, PATHINFO_EXTENSION);
            $name = basename($src, '.' . $ext);
            $dir = dirname($src);
            if (in_array($ext, array('gif', 'jpg', 'jpeg', 'bmp', 'png'))) {
                $name = $name . '_thumb_' . $width . '_' . $height . '.' . $ext;
                $file = $dir . '/' . $name;
                if (!file_exists($file) || $replace == true) {
                    $image = \think\Image::open($src);
                    $image->thumb($width, $height, $type);
                    $image->save($file);
                }
                $file = str_replace("\\", "/", $file);
                $file = '/' . trim($file, './');
                return $file;
            }
        }
        $src = str_replace("\\", "/", $src);
        $src = '/' . trim($src, './');
        return $src;
    }

    /**
     * 是否在微信中
     */
    function in_wechat()
    {
        return strpos($_SERVER['HTTP_USER_AGENT'], 'MicroMessenger') !== false;
    }

    /**
     * 数据签名认证
     * @param  array $data 被认证的数据
     * @return string       签名
     */
    function data_auth_sign($data)
    {
        // 数据类型检测
        if (!is_array($data)) {
            $data = (array)$data;
        }
        ksort($data); // 排序
        $code = http_build_query($data); // url编码并生成query字符串
        $sign = sha1($code); // 生成签名
        return $sign;
    }

    /**
     * 清除系统缓存
     */
    function clear_cache($directory = null)
    {
        $directory = empty($directory) ? root_path() . 'runtime/cache/' : $directory;
        if (is_dir($directory) == false) {
            return false;
        }
        $handle = opendir($directory);
        while (($file = readdir($handle)) !== false) {
            if ($file != "." && $file != "..") {
                is_dir($directory . '/' . $file) ? clear_cache($directory . '/' . $file) : unlink($directory . '/' . $file);
            }
        }
        if (readdir($handle) == false) {
            closedir($handle);
            rmdir($directory);
        }
    }


    // 将 select data 的值，转换成文字。
    function get_select($selectName, $value, $join='，') {
        $arr = config('select_data.'.$selectName);
        if (is_array($value)) {
            $ret = [];
            foreach ($value as $v) {
                $ret[$v] = $arr[$v];
            }
            return implode($join, $ret);
        }else{
            return $arr[$value];
        }
    }
    // 将 select data 的值，转换成文字。
    function list_select($optname,$value) {
        $arr = config('select_data.'.$optname);
        $ret = '';
        foreach ($arr as $k=>$v) {
            if($k==$value){
                $ret .= "<option value=\"$k\" selected>$v</option>";
            }else{
                $ret .= "<option value=\"$k\" >$v</option>";
            }
        }
        return $ret;
    }
    // 将 radio data 的值，转换成文字。
    function list_radio($optname,$value,$name) {
        $arr = config('select_data.'.$optname);
        $ret = '';
        foreach ($arr as $k=>$v) {
            if($k==$value){
                $ret .= "<input type=\"radio\" name=\"$name\" value=\"$k\" title=\"$v\" checked>";
            }else{
                $ret .= "<input type=\"radio\" name=\"$name\" value=\"$k\" title=\"$v\">";
            }
        }
        return $ret;
    }

    /**
     * 获取时间参数
     * @return $the_time 时间戳
     */
    function time_trans($the_time,$both=false)
    {
        $now_time = time();
        // $show_time = strtotime($the_time);
        $dur = $now_time - $the_time;
        if($dur < 60){
            return $dur.'秒前';
        }else if($dur < 3600){
            return floor($dur/60).'分钟前';
        }else if($dur < 86400) {
            return floor($dur/3600).'小时前';
        }else if($dur < 259200) {//3天内
           return floor($dur / 86400) . '天前';
        }else if($both == true){
            return date('Y-m-d',$the_time);
        }else{
            return date('Y-m-d H:i:s',$the_time);
        }
    }
    
    /**
     * 获取某天的开始时间结束时间
     * @param array $time 时间戳
     */
    function get_start_end_time($time)
    {
        // 当天的零点
        $dayBegin = strtotime(date('Y-m-d',$time));
        $data['start'] = $dayBegin;
        // 当天的24
        $data['end'] = $dayBegin + 86400;
        return $data;
    }

    /**
     * 数组转换为数据集对象
     * @param array $resultSet 数据集数组
     * @return \think\model\Collection|\think\Collection
     */
    function collection($resultSet)
    {
        $item = current($resultSet);
        if ($item instanceof Model) {
            return \think\model\Collection::make($resultSet);
        } else {
            return \think\Collection::make($resultSet);
        }
    }
    //加解密
    function md6($str='',$de=false){
        $key= 'gvWFOycl4279';
        $char= 'MDAwMDAwMDAwM';
        if($str!=''){ 
            if($de){
                $str=$char.$str;
                $str=think_decrypt($str,$key);
            }else{
                $str=think_encrypt($str,$key);
                $str=str_replace($char, '',$str);
            }
        }
        return $str;
    }
    /**
    * 系统加密方法
    * @param string $data 要加密的字符串
    * @param string $key 加密密钥
    * @param int $expire 过期时间 单位 秒
    * return string
    */
    function think_encrypt($data, $key = '', $expire = 0) {
        $key = md5(empty($key) ? config('DATA_AUTH_KEY') : $key);
        $data = base64_encode($data);
        $x = 0;
        $len = strlen($data);
        $l = strlen($key);
        $char = '';
        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) $x = 0;
            $char .= substr($key, $x, 1);
            $x++;
        }
        $str = sprintf('%010d', $expire ? $expire + time():0);
        for ($i = 0; $i < $len; $i++) {
            $str .= chr(ord(substr($data, $i, 1)) + (ord(substr($char, $i, 1)))%256);
        }
        return str_replace(array('+','/','='),array('-','_',''),base64_encode($str));
    }

    /**
    * 系统解密方法
    * @param string $data 要解密的字符串 （必须是think_encrypt方法加密的字符串）
    * @param string $key 加密密钥
    * return string
    */
    function think_decrypt($data, $key = ''){
        $key = md5(empty($key) ? config('DATA_AUTH_KEY') : $key);
        $data = str_replace(array('-','_'),array('+','/'),$data);
        $mod4 = strlen($data) % 4;
        if ($mod4) {
            $data .= substr('====', $mod4);
        }
        $data = base64_decode($data);
        $expire = substr($data,0,10);
        $data = substr($data,10);
        if($expire > 0 && $expire < time()) {
            return '';
        }
        $x = 0;
        $len = strlen($data);
        $l = strlen($key);
        $char = $str = '';
        for ($i = 0; $i < $len; $i++) {
            if ($x == $l) $x = 0;
            $char .= substr($key, $x, 1);
            $x++;
        }
        for ($i = 0; $i < $len; $i++) {
            if (ord(substr($data, $i, 1))<ord(substr($char, $i, 1))) {
                $str .= chr((ord(substr($data, $i, 1)) + 256) - ord(substr($char, $i, 1)));
            }else{
                $str .= chr(ord(substr($data, $i, 1)) - ord(substr($char, $i, 1)));
            }
        }
        return base64_decode($str);
    }

    /**
     * 根据主键ID查询关系链(最新)
     * 常用于更新用户关系链
     * @param int $uid 主键ID
     */
    function get_new_genes($uid)
    {
        $res = Db::table('user')->where('id', $uid)->value('parent_id');
        if ($res) {
            $res = $res.',';
            $res.=get_new_genes($res);
            return rtrim($res,',');
        }
    }

    /**
     * 根据主键ID查询关系链
     * 常用于分销、查询上级等
     * @param int $uid 主键ID
     *
     */
    function get_genes_by_id($uid)
    {
        $res = Db::table('user')->where('id', $uid)->value('genes');
        if ($res == null) {
            $res = get_new_genes($uid);
        }
        return $res;
    }
    /**
     * 保存用户账户变动记录
     * @param array $param 变动内容
     */
    function insert_account_log($param)
    {
        $money = empty($param['money'])?0.00:$param['money'];
        $growth = empty($param['growth'])?0:$param['growth'];
        $integral = empty($param['integral'])?0:$param['integral'];
        $money_type = $growth_type = $integral_type = 0;
        if(strpos($money,'-') !== false){
            $money_type = 1;
        }
        if(strpos($growth,'-') !== false){
            $growth_type = 1;
        }
        if(strpos($integral,'-') !== false){
            $integral_type = 1;
        }
        
        $info = Db::table('user')->field('money,growth,integral')->where('id',$param['uid'])->find();
        $res = app\common\model\Account::insert([
            'user_id'               => $param['uid'],
            'money'                 => abs($money),
            'money_before_change'   => $info['money'],
            'money_type'            => $money_type,
            'growth'                => abs($growth),
            'growth_before_change'  => $info['growth'],
            'growth_type'           => $growth_type,
            'integral'              => abs($integral),
            'integral_before_change'=> $info['integral'],
            'integral_type'         => $integral_type,
            'change_desc'           => $param['change_desc'],
            'change_type'           => $param['change_type'],//1管理员调节
            'create_time'           => time(),
        ]);
        if ($res) {
            $save = Db::table('user')->where('id',$param['uid'])->Inc('money',$money)->Inc('growth',$growth)->Inc('integral',$integral)->update();
            update_rank($param['uid']);//根据用户成长值调整用户等级
        }
        return $save;
    }

    /**
     * 根据用户成长值自动修改用户等级
     * @param array $id 会员ID
     */
    function update_rank($id)
    {
        $u_rank = Db::table('user')->field('growth,rank_id')->find($id);
        if ($u_rank['growth']<1) {
            $rank_id = Db::table('rank')->where('status',1)->order('growth','ASC')->limit(1)->value('id');
        }else{
            $rank_id = Db::table('rank')->where('status',1)->where('growth','<=',$u_rank['growth'])->order('growth','DESC')->limit(1)->value('id');
        }
        if($rank_id != $u_rank['rank_id']){
            Db::table('user')->update(['id'=>$id,'rank_id'=>$rank_id]);
        }
    }
